package my.client.service;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.xml.soap.Name;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.TransformerException;

import org.apache.ws.security.util.Base64;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.soap.saaj.SaajSoapMessage;

/**
 * WSSESecurityHeaderRequestWebServiceMessageCallback adds a username token to
 * the header. It retrieves the username and password from the
 * {@link SecurityContextHolder}. It does not encrypt the password before
 * sending it on the wire.
 * 
 * @author Nilaksh Bajpai
 */
public class WSSESecurityHeaderRequestWebServiceMessageCallback implements
		WebServiceMessageCallback {

	public void doWithMessage(WebServiceMessage message) throws IOException,
			TransformerException {

		try {

			// Assumption: We are using the default SAAJWebMessageFactory

			SaajSoapMessage saajSoapMessage = (SaajSoapMessage) message;

			SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();

			SOAPPart soapPart = soapMessage.getSOAPPart();

			SOAPEnvelope soapEnvelope = soapPart.getEnvelope();

			SOAPHeader soapHeader = soapEnvelope.getHeader();

			Name headerElementName = soapEnvelope
					.createName(
							"Security",
							"wsse",
							"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

			// Add "Security" soapHeaderElement to soapHeader
			SOAPHeaderElement soapHeaderElement = soapHeader
					.addHeaderElement(headerElementName);

			// This may be important for some portals!
			soapHeaderElement.setActor(null);

			// Add usernameToken to "Security" soapHeaderElement
			SOAPElement usernameTokenSOAPElement = soapHeaderElement
					.addChildElement(
							"UsernameToken",
							"wsse",
							"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

			// Add username to usernameToken
			SOAPElement userNameSOAPElement = usernameTokenSOAPElement
					.addChildElement(
							"Username",
							"wsse",
							"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

			UserDetails user = (UserDetails) SecurityContextHolder.getContext()
					.getAuthentication().getPrincipal();
			userNameSOAPElement.addTextNode(user.getUsername());

			String password = user.getPassword();
//			String encodedPassword = Base64.encode(MessageDigest.getInstance(
//					"SHA-1").digest(password.getBytes("UTF-8")));
			// Add password to usernameToken
			SOAPElement passwordSOAPElement = usernameTokenSOAPElement
					.addChildElement(
							"Password",
							"wsse",
							"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

			passwordSOAPElement.addTextNode(password);

		} catch (SOAPException soapException) {
			throw new RuntimeException(
					"WSSESecurityHeaderRequestWebServiceMessageCallback",
					soapException);
//		} catch (NoSuchAlgorithmException e) {
//			throw new RuntimeException(
//					"WSSESecurityHeaderRequestWebServiceMessageCallback", e);
		}
	}
}
